package auth

import (
	"5title_gin/global"
	"5title_gin/internal/model/user"
	"5title_gin/pkg/cache"
	"5title_gin/pkg/db/crud"
	"5title_gin/pkg/utils/crypto"
	"5title_gin/pkg/utils/jwts"
	"5title_gin/pkg/utils/sys/userUtils"
	"errors"
	"fmt"
	"time"
)

type AuthService struct {
	userCrud *crud.CRUD[user.UserModel]
}

func NewAuthService() *AuthService {
	return &AuthService{
		userCrud: crud.NewCRUD[user.UserModel](global.DB),
	}
}

// Login 用户登录
func (s *AuthService) Login(req user.LoginRequest) (string, string, error) {
	// 检查锁定状态
	locked, err := cache.CheckLock(req.Username)
	if err != nil {
		return "", "", errors.New("系统错误，请稍后再试！")
	}
	if locked {
		return "", "", errors.New("账号已锁定，请稍后再试！")
	}

	models, err := s.userCrud.GetAll().Where("username", req.Username).Find()
	if err != nil {
		return s.handleLoginFailure(req.Username)
	}
	if len(models) == 0 {
		return s.handleLoginFailure(req.Username)
	}
	var userModel = models[0]

	// 验证密码
	if !crypto.CompareHashAndPassword(userModel.Password, req.Password) {
		return s.handleLoginFailure(req.Username)
	}

	// 生成 Token
	accessToken, refreshToken, err := jwts.GenerateToken(jwts.Claims{
		RoleID: userModel.RoleID,
		UserID: userModel.ID,
	})
	if err != nil {
		return "", "", errors.New("生成 Token 失败")
	}

	// 存储 Token
	if err = cache.StoreAccessToken(userModel.ID, accessToken); err != nil {
		return "", "", errors.New("存储 Access Token 失败")
	}
	if err = cache.StoreRefreshToken(userModel.ID, refreshToken); err != nil {
		return "", "", errors.New("存储 Refresh Token 失败")
	}
	if err := cache.SetUserInfo(userModel.ID); err != nil {
		return "", "", errors.New("存储用户信息失败")
	}

	// 更新最后登录时间
	userModel.LastLogin = time.Now().Format("2006-01-02 15:04:05")
	if err := s.userCrud.Update(&userModel); err != nil {
		return "", "", errors.New("更新最后登录时间失败")
	}

	// 登录成功，清除失败记录
	if err := cache.ClearFailedAttempts(req.Username); err != nil {
		return "", "", errors.New("清除失败记录失败")
	}

	// 更新用户状态
	if err := userUtils.UpdateUserStatus(userModel.ID, 1); err != nil {
		// 这里只记录错误，不影响登录流程
		// zap.S().Errorf("更新用户 %d 状态为在线失败: %v", userModel.ID, err)
	}

	return accessToken, refreshToken, nil
}

// 处理登录失败
func (s *AuthService) handleLoginFailure(username string) (string, string, error) {
	currentAttempts, maxAttempts, err := cache.IncrementFailedAttempts(username)
	if err != nil {
		return "", "", errors.New("系统错误，请稍后再试")
	}

	remainingAttempts := maxAttempts - currentAttempts
	if remainingAttempts > 0 {
		return "", "", fmt.Errorf("用户名或密码错误，您还可以尝试 %d 次", remainingAttempts)
	} else {
		locked, _ := cache.CheckLock(username)
		if locked {
			return "", "", errors.New("账号已锁定，请稍后再试！")
		} else {
			return "", "", errors.New("用户名或密码错误，尝试次数已用尽")
		}
	}
}

// RefreshToken 刷新令牌
func (s *AuthService) RefreshToken(refreshToken string) (string, error) {
	// 解析 Refresh Token 获取用户信息
	userClaims, err := jwts.GetClaimsFromRefreshToken(refreshToken)
	if err != nil {
		return "", errors.New("解析 Refresh Token 失败")
	}

	// 获取存储的 Refresh Token
	storedRefreshToken, err := cache.GetRefreshToken(userClaims.Claims.UserID)
	if err != nil || storedRefreshToken == "" {
		return "", errors.New("Refresh Token 未找到或已失效")
	}

	// 验证 Refresh Token 是否匹配
	if storedRefreshToken != jwts.HashToken(refreshToken) {
		return "", errors.New("Refresh Token 不匹配")
	}

	// 解析 Refresh Token
	claims, err := jwts.CheckToken(refreshToken)
	if err != nil {
		return "", errors.New("Refresh Token 无效或已过期")
	}

	// 生成新的 Access Token
	newAccessToken, _, err := jwts.GenerateToken(jwts.Claims{
		UserID: claims.Claims.UserID,
		RoleID: claims.Claims.RoleID,
	})
	if err != nil {
		return "", errors.New("生成新的 Access Token 失败")
	}

	// 存储新的 Access Token
	if err = cache.StoreAccessToken(claims.Claims.UserID, newAccessToken); err != nil {
		return "", errors.New("存储新的 Access Token 失败")
	}

	return newAccessToken, nil
}

// Logout 用户登出
func (s *AuthService) Logout(token string, userID uint) error {
	// 执行登出操作
	msg := cache.Logout(token, userID)
	if msg != "" {
		return errors.New(msg)
	}

	// 更新用户状态为离线
	if err := userUtils.UpdateUserStatus(userID, 2); err != nil {
		return errors.New("更新用户状态失败")
	}

	return nil
}

// ChangePassword 修改密码
func (s *AuthService) ChangePassword(userID uint, oldPassword, newPassword string) error {
	// 获取用户信息
	userModel, err := s.userCrud.GetByID(userID)
	if err != nil {
		return errors.New("获取用户信息失败")
	}

	// 校验旧密码
	if !crypto.CompareHashAndPassword(userModel.Password, oldPassword) {
		return errors.New("旧密码错误")
	}

	// 生成新密码
	hashedPassword, err := crypto.GenerateFromPassword(newPassword)
	if err != nil {
		return errors.New("密码加密失败")
	}

	// 更新密码
	userModel.Password = hashedPassword
	if err := s.userCrud.Update(userModel); err != nil {
		return errors.New("修改密码失败")
	}

	return nil
}
